import tkinter as tk
from abc import abstractmethod
import common.common as common
from common.common import text_format_type_from_string

from links.abstract_link_ui import AbstractUiLink
from .page_io_input import PageInput
from .page_io_output import PageOutput
from .page_io import PageIo
from .page_settings import PageSettings


class AbstractPage(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.output_frame = PageOutput(self)
        self.input_frame = PageInput(self)
        self.io_frame = PageIo(self)
        self.settings_frame = PageSettings(self)
        self.settings_frame.link_settings.page = self
        self.settings_frame.output_settings.text = self.output_frame.text
        self.settings_frame.output_settings.update_wrap_mode()
        self.settings_frame.input_settings.page = self
        self.setup_text_format_for_entry()

    @abstractmethod
    def create_controller(self, io_settings) -> AbstractUiLink:
        pass

    def io_settings(self):
        return self.settings_frame.link_settings

    def init_ui(self):
        controller = self.create_controller(io_settings=self.io_settings())
        self.settings_frame.init_ui(controller)

        self.settings_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
        self.output_frame.grid(row=0, column=1, sticky="nsew")
        self.input_frame.grid(row=1, column=1, sticky="nsew")
        self.io_frame.grid(row=0, column=1, rowspan=2, sticky="nsew")
        # self.io_frame.init_ui(controller)
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)

    def input_data(self):
        text_format = self.settings_frame.input_settings.text_format()
        cooked_format = common.text_format_type_from_string(text_format)
        text = self.input_frame.text_entry.get()
        if text == "":
            return

        data = common.string_to_binary_array(text, cooked_format)
        self.settings_frame.link_settings.input_data(data)

    def output_data(self, data_item: dict):
        data = data_item["data"]
        flag = data_item["flag"]
        rx = data_item["rx"]

        parameters = self.settings_frame.output_settings.parameters()
        # print(f"{parameters}{data_item}")

        text_format = text_format_type_from_string(parameters["format"])
        show_date = parameters["show_date"]
        show_time = parameters["show_time"]
        show_millis = parameters["show_millis"]
        show_rx = parameters["show_rx"]
        show_tx = parameters["show_tx"]

        if not show_rx and rx:
            return

        if not show_tx and not rx:
            return

        # get date string with loaded format
        data_str = ""
        if show_date:
            data_str += common.current_date_string()

        # get time string with loaded format
        time_str = ""
        if show_time:
            time_str = common.current_time_string()

        millis_string = ""
        if show_millis:
            millis_string = common.current_millis_string()

        date_time_string = f"{data_str} {time_str} {millis_string}"
        date_time_string = date_time_string.strip()

        flag_str = ""
        if flag:
            flag_str = f"{flag}"

        header_string = f"{date_time_string} {flag_str}"
        header_string = header_string.strip()
        header_string = f"{'RX' if rx else 'TX'}({header_string})"
        header_string = f"[{header_string}]"

        cooked_text = common.binary_bytes_to_string(data, text_format)
        self.output_frame.output_data(f"{header_string}: {cooked_text}")

    def setup_text_format_for_entry(self):
        txt_fmt = self.settings_frame.input_settings.text_format()
        entry = self.input_frame.text_entry
        cooked_txt_fmt = text_format_type_from_string(txt_fmt)
        common.setup_text_format_for_entry(entry, cooked_txt_fmt)
        print(f"setup_text_format_for_entry: {txt_fmt}")
